package snapex.core.security;

import javax.servlet.http.HttpServletRequest;
import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.web.util.matcher.RequestMatcher;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Configuration
@EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {

	@Configuration
	@EnableWebSecurity
	static class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {

//		@Value("snapex.security.userStore")
//		private String userStore;
//
//		@Autowired
//		private DataSource dataSource;
//		
//		@Override
//		protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//
//			log.debug("*****User Store:{}", userStore);
//			
//			if("Memory".equalsIgnoreCase(userStore)) {
//				auth.inMemoryAuthentication()
//					.withUser("user").password("user").roles("USER")
//					.and()
//					.withUser("admin").password("admin").roles("ADMIN")
//					;
//			}			
//			else if("Jdbc".equalsIgnoreCase(userStore)) {
//				auth.jdbcAuthentication()
//					.dataSource(dataSource)
//					.usersByUsernameQuery("select username,password,enabled from users where username = ?")
//					.authoritiesByUsernameQuery("select username,authority from authorities where username = ?")
//					.groupAuthoritiesByUsername("select g.id, g.group_name, ga.authority from groups g, group_members gm, group_authorities ga where gm.username = ? and g.id = ga.group_id and g.id = gm.group_id")				
//					;
//			}
//			else if("Ldap".equalsIgnoreCase(userStore)) {
//				auth.ldapAuthentication().userSearchBase("ou=people").userSearchFilter("(uid={0})")
//				.groupSearchBase("ou=groups").groupSearchFilter("member={0}").contextSource()
//				.root("dc=baeldung,dc=com").ldif("classpath:users.ldif");
//			}						
//		}

		@Override
		@Bean
		public AuthenticationManager authenticationManagerBean() throws Exception {
			return super.authenticationManagerBean();
		}

		@Override
		public void configure(HttpSecurity http) throws Exception {
			http.authorizeRequests()					
					.antMatchers("/user/register","/user/wxacode","/resources/**","/").permitAll()
					.anyRequest().authenticated()
				.and()
				.formLogin()
					.loginPage("/login").permitAll()
					.failureForwardUrl("/login/error")
				.and()
					.logout()
					.logoutUrl("/logout").permitAll();
			
			http.csrf().ignoringAntMatchers("/user/register");
		}
	}

	// @formatter:off
	@Override
	public void configure(HttpSecurity http) throws Exception {
		log.debug("***ResourceServerConfiguration:configure(HttpSecurity http): {}", http);

		RequestMatcher rm = new RequestMatcher() {
			@Override
			public boolean matches(HttpServletRequest request) {
				boolean isMatched = false;
				
				if("HEAD".equalsIgnoreCase(request.getMethod())){
					return isMatched;
				}
				
				String authorization = request.getHeader("Authorization");
				if (authorization != null && (authorization.startsWith(OAuth2AccessToken.BEARER_TYPE) || authorization.startsWith("Basic"))) {
					isMatched = true;
					log.debug("*****requestURI[{}], Authorization[{}]", request.getRequestURI(), authorization);
				}
				// check if access token exists
				String accessToken = request.getParameter(OAuth2AccessToken.ACCESS_TOKEN);
				if (accessToken != null) {
					isMatched = true;
					log.debug("*****requestURI[{}], Access_token[{}]", request.getRequestURI(), accessToken);
				}
				
				if(log.isDebugEnabled()){
					log.debug("RequestMatcher: isMatched:{}, authorization:{}, accessToken:{}, requestURI:{}, method:{}, RemoteAddr:{}",
						isMatched, authorization, accessToken, request.getRequestURI(), request.getMethod(), request.getRemoteAddr());
				}
				
				return isMatched;
			}
		};
		
		http.requestMatcher(rm)
			.authorizeRequests()
			.anyRequest().authenticated();
		
	}
	// @formatter:on
}
